#pragma once
#include <Windows.h>
#include <queue>
#include <list>
#include <string>
#include <atomic>
#include <algorithm>

class CFileFinder
{
private:
    std::queue<std::string> m_DirsQueue;
    std::atomic<unsigned int> m_nThreadCnt;
    std::atomic<unsigned int> m_nActiveThreadCnt;
    std::string m_strMatchFileName;
    CRITICAL_SECTION m_cs;
    std::list<std::string>* m_lpFileList;
    std::list<std::string>* m_lpDirList;
    HANDLE m_hSyncEvent;
    HANDLE m_hWaitEvent;
    BOOL m_bFullWordMatch;
    BOOL m_bInto;
    static std::atomic<size_t> m_stFileTotal;
    static std::atomic<size_t> m_stDirTotal;
    BOOL m_bCaseInSensitive;

public:
    CFileFinder();
    ~CFileFinder();

protected:
    static DWORD WINAPI Adaptor(IN LPVOID lpParam);
    void SearchFileWorker();
    void CreateThreadAndWait();
    size_t Search(IN std::string strDirName, IN std::string strFileName, OUT std::list<std::string>* lpFileList, OUT std::list<std::string>* lpDirList, IN BOOL bFullWordMatch, IN BOOL bCaseInSensitive, IN BOOL bInto);
    size_t Search(IN const std::queue<std::string>& DirsQueue, IN std::string strFileName, OUT std::list<std::string>* lpFileList, OUT std::list<std::string>* lpDirList, IN BOOL bFullWordMatch, IN BOOL bCaseInSensitive, IN BOOL bInto);

public:
    static CFileFinder* GetInstance();
    static size_t SearchFile(IN std::string strDirectoryName, IN std::string strFileName, OUT std::list<std::string>* lpFileList, IN BOOL bFullWordMatch, IN BOOL bCaseInSensitive, IN BOOL bInto);
    static size_t SearchFile(IN const std::queue<std::string>& DirsQueue, IN std::string strFileName, OUT std::list<std::string>* lpFileList, IN BOOL bFullWordMatch, IN BOOL bCaseInSensitive, IN BOOL bInto);
    static size_t TraverseDirectory(IN std::string strDirectoryName, OUT std::list<std::string>* lpFileList, OUT std::list<std::string>* lpDirList, IN BOOL bInto);
    static size_t TraverseDirectory(IN const std::queue<std::string>& DirsQueue, OUT std::list<std::string>* lpFileList, OUT std::list<std::string>* lpDirList, IN BOOL bInto);
    static size_t GetDirTotal() { return m_stDirTotal; }
    static size_t GetFileTotal() { return m_stFileTotal; }
};
